package module02.task02;

import java.util.Scanner;

/**
 * 编程实现控制台版并支持两人对战的五子棋游戏。
 *
 * （1）绘制棋盘 - 写一个成员方法实现
 *
 * （2）提示黑方和白方分别下棋并重新绘制棋盘 - 写一个成员方法实现。
 *
 * （3）每当一方下棋后判断是否获胜 - 写一个成员方法实现。
 *
 * （4）提示： 采用二维数组来模拟并描述棋盘，棋盘如下
 */
public class BoardGame {
    private final static int BOARD_WIDTH = 17;
    private enum Turn {BLACK, WHITE}

    private char[][] board;
    public Turn turn;

    /**
     * 构造函数：创建棋盘，设置初始玩家为白子
     */
    public BoardGame(){
        initBoard();
        turn = Turn.WHITE;
    }

    /**
     * 开始游戏，两个玩家交替输入棋步，直到有一方获胜
     */
    public void startGame(){
        int[] input = takeInput();
        while(!isWon(input[0],input[1])){
            if (turn == Turn.BLACK) turn = Turn.WHITE;
            else turn = Turn.BLACK;
            input = takeInput();
        }
        System.out.println("恭喜玩家"+ turn + "，你刚刚赢得了比赛！");
    }

    /**
     * 检查当前走棋是否使当前玩家获胜（是否形成五子连珠）
     * @param x 当前棋步的x坐标
     * @param y 当前棋步的y坐标
     * @return 是否获胜
     */
    private Boolean isWon(int x, int y){
        int sum = 0;
        int target = (turn == Turn.BLACK)? 'B':'W';

        /* 检查策略：以当前棋步为中心，检查左右，上下，四个方向斜向的相邻5子，看看是否有同色连续5子 */

        // ============检查横向5子连珠============
        // 先往此子左边
        int i = 5;
        int flag = y;
        while(i != 0 && flag>0) {
            if (board[x][flag] == target) {
                sum ++;
                i --;
                flag --;
            }
            else break;
        }
        // 再往此子右边
        i = 5;
        flag = y + 1;
        while(i != 0 && flag<17) {
            if (board[x][flag] == target) {
                sum ++;
                i --;
                flag ++;
            }
            else break;
        }
        if (sum >= 5) return true;

        // ============检查纵向五子连珠============
        sum = 0;
        // 先往上
        i = 5;
        flag = x;
        while(i != 0 && flag>0) {
            if (board[x][flag] == target) {
                sum ++;
                i --;
                flag --;
            }
            else break;
        }
        // 再往此子下面
        i = 5;
        flag = x + 1;
        while(i != 0 && flag<17) {
            if (board[x][flag] == target) {
                sum ++;
                i --;
                flag ++;
            }
            else break;
        }
        if (sum >= 5) return true;

        // ============检查左上到右下五子连珠============
        sum = 0;
        // 先往左上
        i = 5;
        int flagX = x;
        int flagY = y;
        while(i != 0 && flagX>0 && flagY>0) {
            if (board[flagX][flagY] == target) {
                sum ++;
                i --;
                flagX --;
                flagY --;
            }
            else break;
        }
        // 再往右下
        flagX = x + 1;
        flagY = y + 1;
        while(i != 0 && flagX<17 && flagY<17) {
            if (board[x][flag] == target) {
                sum ++;
                i --;
                flagX --;
                flagY --;
            }
            else break;
        }
        if (sum >= 5) return true;

        // ============检查右上到左下五子连珠============
        sum = 0;
        // 先往右上
        i = 5;
        flagX = x;
        flagY = y;
        while(i != 0 && flagX<17 && flagY>0) {
            if (board[flagX][flagY] == target) {
                sum ++;
                i --;
                flagX ++;
                flagY --;
            }
            else break;
        }
        // 再往左下
        flagX = x - 1;
        flagY = y + 1;
        while(i != 0 && flagY<17 && flagX>0) {
            if (board[x][flag] == target) {
                sum ++;
                i --;
                flagX --;
                flagY ++;
            }
            else break;
        }
        if (sum >= 5) return true;

        return false;
    }

    /**
     * 读取玩家输入的棋步，并在棋盘上更新该步
     * @return 一个两个元素的一维整型数组，分别表示当前棋步的xy坐标
     */
    public int[] takeInput(){
        System.out.println("玩家" + turn + "，轮到你落子了！");
        System.out.println("请依次输入行号(1~16)，列号(1~16)，用空格分开：");

        Scanner sc = new Scanner(System.in);
        Boolean isLegal = false;
        int x = 0, y = 0;
        while(!isLegal){
            x = sc.nextInt();
            y = sc.nextInt();
            System.out.println("玩家" + turn + "落子在：第" + x + "行，" + "第"+ y+ "列。");
            if(x<1 || y<1 || x>16 || y>16) System.out.println("呀！落子在棋盘外面了，请重新落子哟～");
            else if('+' != board[x][y]) System.out.println("呀！落子和别的棋子重合了，请重新落子哟～");
            else isLegal = true;
        }
        if(turn == Turn.BLACK) board[x][y] = 'B';
        else board[x][y] = 'W';
        printBoard();
        int[] input = {x, y};
        return input;

    }

    /**
     * 打印当前棋盘
     */
    private void printBoard(){
        for(int row=0; row<board.length; row++) {
            for(int col=0; col<board[row].length; col++) {
                System.out.print(board[row][col] + "   ");
            }
            System.out.println();
        }
    }

    /**
     * 创建棋盘
     */
    private void initBoard(){
        System.out.println("====================创建棋盘======================");
        board = new char[BOARD_WIDTH][BOARD_WIDTH];

        // 填充 + 号
        for(int row=1; row<BOARD_WIDTH; row++) {  //行
            for(int col=1; col<BOARD_WIDTH; col++) {  //列
                board[row][col] = '+';
            }
        }

        // 填充首行，遍历列
        for(int col=1; col<BOARD_WIDTH; col++) {
            if(col < 11)
                board[0][col] = (char)(47 + col);
            else
                board[0][col] = (char)(86 + col);
        }

        // 填充首列，遍历行
        for(int row=1; row<BOARD_WIDTH; row++) {
            if(row < 11)
                board[row][0] = (char)(47 + row);
            else
                board[row][0]= (char)(86 + row);
        }

        // 填充头角
        board[0][0] = ' ';
        printBoard();
    }
}
